#include <Poco/Thread.h>
#include "TCPServerPacketReceiverWrapper.h"

namespace network
{

template<typename PacketType, typename PacketReaderWriterType>
TCPServerPacketReceiverWrapper<PacketType, PacketReaderWriterType>::TCPServerPacketReceiverWrapper(PacketReaderWriterType& io)
: _io(io)
{
}

template<typename PacketType, typename PacketReaderWriterType>
TCPServerPacketReceiverWrapper<PacketType, PacketReaderWriterType>::~TCPServerPacketReceiverWrapper()
{
}

template<typename PacketType, typename PacketReaderWriterType>
typename PacketType::Ptr TCPServerPacketReceiverWrapper<PacketType, PacketReaderWriterType>::recv()
{
	if (_packet.getData() == nullptr)
	{
		char* pHeader = _packet.getHeader();
		//int n = socket.receiveBytes(, 4 - _readLen, 0);
		_readLen += recv((char *)&(((char *)pHeader)[_readLen]), _packet.getHeaderSize() - _readLen);
		//std::cout << "received packet header length: " << _readLen << std::endl;
		if (_readLen == _packet.getHeaderSize())
		{
			std::string errmsg;
			bool blRet = _packet.validateHeader(errmsg);
			if (!blRet)
			{
				//std::cout << errmsg << std::endl;
				throw Poco::DataFormatException(errmsg);
			}

			_packet.allocData();
			_readLen = 0;
		}
		else
		{
			return nullptr;
		}
	}

	_readLen += recv((char *)&_packet.getData()[_readLen], _packet.getDataSize() - _readLen);
	if (_readLen == _packet.getDataSize())
	{
		_readLen = 0;

		typename PacketType::Ptr packet = new PacketType(_packet);
		return packet;
	}

	return nullptr;
}

template<typename PacketType, typename PacketReaderWriterType>
inline int network::TCPServerPacketReceiverWrapper<PacketType, PacketReaderWriterType>::recv(char* buff, int size)
{
	int n = 0;
	Timestamp tsStartRecv;

	n = _io.read(buff, size);
	if (n == 0)
	{
		std::string str = "peer socket closed";
		//std::cout << str << std::endl;
		throw Poco::Net::ConnectionResetException(str);
	}
	else if (n < 0)
	{
		Thread::sleep(100);
		if (_timeout > 0 && tsStartRecv.isElapsed(_timeout))
		{
			std::string str = "socket receiving timeout.";
			//std::cout << str << std::endl;
			throw Poco::TimeoutException(str);
		}
//		std::string str = "socket error occurred when receiving, return code = " + std::to_string(n);
//		std::cout << str << std::endl;
//		throw Poco::Net::NetException(str);
	}
//	else
//	{
//		//std::cout << "ddddddddddddddddddddd: length = " << n << std::endl;
//	}

	return n;
}

}
